package HereClass;

/**
 * Classe responsavel por gerenciar o evio e recebimento de convites
 * @author Caio, Ronaldo, Enio e Rafael
 * @version 5.1
 */

import java.util.ArrayList;

import source.com.maxmind.geoip.LookupService;
import Exceptions.ObterLocalizacaoException;
import Exceptions.OffLineException;
import Exceptions.SetLocalizacaoException;
import Exceptions.UsuarioException;
import Facade.FachadaDeArmazenamento;


public class Compartilhador {

	private UsuariosConectados usuariosConectados;
	private final String LOCALIZADORES = "[GeoIP, Manual]";
	private final int USUARIO_INEXISTENTE = -1;
	private final String IP_INVALIDO = "N/A";
	private FachadaDeArmazenamento fachadaDeArmazenamento;

	public Compartilhador() {
		this.usuariosConectados = UsuariosConectados.getInstance();
		this.fachadaDeArmazenamento = FachadaDeArmazenamento.getInstance();
	}



	public ArrayList<String> getConvitesPendentes (String email) {
		ArrayList<String> convites = new ArrayList<String>();
		int indice=1;
		Convite convite = fachadaDeArmazenamento.pesquisaConvite(email, indice);
		while(convite!=null && convite.getTo().equals(email)){
			convites.add(convite.getFrom());
			indice++;
			convite = fachadaDeArmazenamento.pesquisaConvite(email, indice);
		}
		for (int i = 0; i < convites.size(); i++) {
			System.out.println(convites.get(i));
		}
		return convites;
}
	
	public boolean removeConvite (String id, String de) {
		Convite convite = new Convite(de, usuariosConectados.getUsuario(id).getEmail());
		return this.fachadaDeArmazenamento.deletaConvite(convite);
	}
	/**
	 * Este metodo confirma a aceitacao de convite de um usuario
	 * 
	 * @param de
	 * @param com
	 * @param modo
	 */
	public void confirmar(int de, String com, int modo) {
		
		Conectavel usuarioCom = usuariosConectados.getUsuarioConectadoByUserName(com);
		if(usuarioCom==null)
			usuarioCom = fachadaDeArmazenamento.pesquisaUsuario(com,1);
		Contato contatoDe = new Contato(usuarioCom.getUserName(), usuarioCom
				.getNome(), modo);
		Conectavel usuarioDe = usuariosConectados.getUsuario(String.valueOf(de));
		usuarioDe.addContato(contatoDe);

		//aceito
		
		Contato contatoCom = new Contato(usuarioDe.getUserName(), usuarioDe
				.getNome(), 2);
		usuarioCom.addContato(contatoCom);
		fachadaDeArmazenamento.atualizaBancoDeDados(usuarioCom);		
	}
	
	public void recusarCompartilhamento(String de, String com) {
		this.fachadaDeArmazenamento.deletaConvite(new Convite(de, com));		
	}

	/**
	 * Este metodo verifica se um usuario pode ver a localizacao de outro.
	 * @param id
	 * @param amigo
	 * @exception OffLineExceptio caso o amigo esteja offline
	 * @exception UsuarioDesconhecdoException caso o amigo seja desconhecido
	 */
	
	public boolean possoVerLocalizacao(String id, String amigo)
			throws OffLineException, UsuarioException {

		Conectavel eu = usuariosConectados.getUsuario(id);
		if (eu == null)
			throw new OffLineException("Permissao negada.");
		Contato meuContato = eu.getContato(amigo);
		if (meuContato == null)
			throw new UsuarioException("Usuario desconhecido.");
		Conectavel user = usuariosConectados.getUsuarioConectadoByUserName(amigo);
		if(user==null)
			user = fachadaDeArmazenamento.pesquisaUsuario(amigo,1);
		Contato contato = user.getContato(eu.getUserName());
		if (contato.getModo() == 2)
			return true;
		return false;
	}

	/**
	 * Este metodo set o modo de compartilhamento entre dois usuarios
	 * @param id
	 * @param amigo
	 * @param modo
	 * @exception UsuarioDesconhecidoException caso o usuario seja desconhecido
	 */
	public void setCompartilhamento(String id, String amigo, int modo)
			throws OffLineException, UsuarioException {
		Conectavel eu = usuariosConectados.getUsuario(id);
		if (eu == null)
			throw new OffLineException("Permissao negada.");
		Contato contato = eu.getContato(amigo);
		if (contato == null)
			throw new UsuarioException("Usuario desconhecido.");
		contato.setModo(modo);
		eu.deleteContato(contato);
		eu.addContato(contato);
		fachadaDeArmazenamento.atualizaBancoDeDados(eu);

	}

	
	/**
	 * Este metodo remove um amigo da lista do usuario
	 * @param id
	 * @param amigo
	 * @exception Caso o IP seja invalido
	 */
	public void removerAmigo(String id, String amigo) 
					throws OffLineException, UsuarioException {
		Conectavel user = usuariosConectados.getUsuario(String.valueOf(id));
		if (user == null)
			throw new OffLineException("Permissao negada.");
		Contato contato = user.getContato(amigo);
		boolean removeu = user.deleteContato(contato);
		if (!removeu)
			throw new UsuarioException("Usuario desconhecido.");

		fachadaDeArmazenamento.atualizaBancoDeDados(user);
		Usuario user2 = (Usuario)fachadaDeArmazenamento.pesquisaUsuario(amigo,1);
		contato = user2.getContato(user.getUserName());
		user2.deleteContato(contato);
		fachadaDeArmazenamento.atualizaBancoDeDados(user2);

	}

	/**
	 * Este metodo retorna uma String contendo os amigos de um usuario
	 * @param de
	 * @return Strin contende os nomes dos amigos de um usuario
	 * @throws Exception
	 * 			UsuarioNaoAutenticado, caso o usuario nao esteja logado
	 */
	public String getAmigos(String de) throws UsuarioException {
		Conectavel usuario;
		int id1 = TransformaString.toInt(de);
		if (id1 == -1)
			throw new UsuarioException("Permissao negada.");
		usuario = usuariosConectados.getUsuario(String.valueOf(de));
		return usuario.getListaDeAmigos();
	}
	
	public String getLocalizacaoAmigo(String id, String amigo) 
							throws UsuarioException, OffLineException {
		int id1 = TransformaString.toInt(id);
		if(id1 == -1)
			throw new UsuarioException("Permissao negada.");
		
		int temp = 1;
		if (possoVerLocalizacao(id, amigo) == true){
			temp = 2;
		}
		
		Conectavel usuarioAmigo = usuariosConectados.getUsuarioConectadoByUserName(amigo);
		if(usuarioAmigo==null)
			usuarioAmigo = (Usuario)fachadaDeArmazenamento.pesquisaUsuario(amigo,1);
		
		if (temp == 2){
			String saida = "Lat: " + usuarioAmigo.getLatitude()
							+ ", Long: " + usuarioAmigo.getLongitude();
			return saida;
		}else{
			return "Localizacao desconhecida.";
		}
		
	}
	
	public String getLocalizadores(){
		return LOCALIZADORES;
	}
	
	/**
	 * Este metodo retorna a localizacao do usuario.
	 * @param id
	 * @exception Caso o IP seja invalido
	 */
	public String obterLocalizacao(String id) throws ObterLocalizacaoException, Exception{		
		String localizacao = null;

		String dbfile = "GeoIP.dat"; 
		LookupService cl = new LookupService(dbfile,LookupService.GEOIP_MEMORY_CACHE);
		
		localizacao = cl.getCountry(usuariosConectados.getUsuario(id).getIP()).getName();

		if (localizacao.equals(IP_INVALIDO))
			throw new ObterLocalizacaoException("Nao foi possivel obter a localizacao.");
		
		return localizacao;
	}
	
	/**
	 * Este metodo seta a localizacao do usuario a partir da sua longitude e latitude.
	 * @param latitude
	 * @param longitude
	 * @exception Caso a latitude/longitude estao invalidos
	 */
	public void setLocalizacao(String id, String latitude, String longitude) 
										throws UsuarioException, SetLocalizacaoException{
		int id1 = TransformaString.toInt(id);
		if(id1 == USUARIO_INEXISTENTE)
			throw new UsuarioException("O usuario nao existe.");
		
		if (usuariosConectados.getUsuario(id) == null ||
				id1 > usuariosConectados.getCapacidadeDoSistema())
			throw new UsuarioException("O usuario nao existe.");
		
		if (latitude.length() == 0 || latitude.length() == 0 || latitude.charAt(0) != '-' ||
				longitude.charAt(0) != '-'){
			throw new SetLocalizacaoException("Latitude/Longitude invalidos.");
		}
		
		Conectavel user = usuariosConectados.getUsuario(id);
		user.setLatitude(latitude);
		user.setLongitude(longitude);
	}
	
	
	/**
	 * Este metodo retorna a localizacao do usuario.
	 * @param id do usuario
	 */
	public String getLocalizacao(String id){
		Conectavel usuario = usuariosConectados.getUsuario(id);
		String localizacao = null;
		if (usuario!=null) localizacao = "Lat: "+ usuario.getLatitude() +
										", Long: " + usuario.getLongitude();
		return localizacao;
	}


}
